package ru.compscicenter.uno.view;

import ru.compscicenter.uno.model.Card;
import ru.compscicenter.uno.model.IModel;
import ru.compscicenter.uno.model.Player;
import ru.compscicenter.uno.view.events.DropCardEvent;
import ru.compscicenter.uno.view.events.DropCardListener;

import javax.swing.*;
import javax.swing.event.EventListenerList;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import static ru.compscicenter.uno.model.Card.Color.*;

/**
 * Created by IntelliJ IDEA.
 * User: Павел
 * Date: 26.11.11
 * Time: 2:23
 * To change this template use File | Settings | File Templates.
 */
public class MyPlayerPanel extends JComponent{
    private Player player;
    PlayerPanel playerPanel;
    ImageButton alreadySayUno;
    ImageButton sayUno;
    
    private final static int PLAYER_PANEL_WIDTH = 200;
    private final static int PLAYER_PANEL_HEIGHT = 50;

    private ArrayList<CardImage> cards = new ArrayList<CardImage>();
    private int cardWidth;
    private int cardHeight;

    public MyPlayerPanel(Player player) {
        this.player = player;

        setLayout(null);
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                resizeElements();
            }
        });

        playerPanel = new PlayerPanel(player);        
        add(playerPanel);

        for (Card card : player.getCards()) {
            addCard(card);
        }
    }

    public PlayerPanel getPlayerPanel() {
        return playerPanel;
    }

    public void setPlayer(Player player) {
        this.player = player;
        playerPanel.setPlayer(player);
    }

    public void update(boolean isMyTurn) {

        for (CardImage card : cards) {
            remove(card);
        }
        cards.clear();

        for (Card card : player.getCards()) {
            addCard(card);
        }

        System.out.println(player.isSaidUno());
        if(player.isSaidUno()){
            playerPanel.setButton(alreadySayUno);
        } else {
            playerPanel.setButton(sayUno);
        }
        
        playerPanel.update(isMyTurn);
    }

    public void setAlreadySayUno(ImageButton alreadySayUno) {
        this.alreadySayUno = alreadySayUno;
    }

    public void setSayUno(ImageButton sayUno) {
        this.sayUno = sayUno;
    }

    public void addCard(final Card card) {
        final CardImage cardImage = new CardImage(card);

        cardImage.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("Clicked on my card (" + cardImage.getCard() + ")");
                if (cardImage.getCard().isColored()) {
                    fireDropCardEvent(new DropCardEvent(this, cardImage, cardImage.getCard().getColor()));
                } else {

                    Frame frame = JOptionPane.getFrameForComponent(cardImage);
                    Card.Color color = SelectColorDialog.showDialog(frame, cardImage, "Выбери цвет");
                    fireDropCardEvent(new DropCardEvent(this, cardImage, color));
                }
            }
        });

        cards.add(getPositionForNewCardWithPriority(card), cardImage);

        add(cardImage);

        resizeElements();
    }

    private int getPositionForNewCardWithPriority(Card newCard) {
        int position = 0;
        for (int i = cards.size() - 1; i >= 0; --i) {
            Card card = cards.get(i).getCard();
            if (getViewCardPriority(newCard) > getViewCardPriority(card)) {
                position = i + 1;
                break;
            }
        }
        return position;
    }

    private int getViewCardPriority(Card card) {
        //приоритет для визуального отображения карты складывается из её значения и цвета. 
        //цвет обладает большим весом, чем значение. 
        //т.о. карты группируются по цвету и по значимости в рамках одного цвета.
        int cardColorPriority = 0;
        int cardTypePriority = 0;

        switch (card.getType()) {
            case NUM_0:
                cardTypePriority = 0;
                break;
            case NUM_1:
                cardTypePriority = 1;
                break;
            case NUM_2:
                cardTypePriority = 2;
                break;
            case NUM_3:
                cardTypePriority = 3;
                break;
            case NUM_4:
                cardTypePriority = 4;
                break;
            case NUM_5:
                cardTypePriority = 5;
                break;
            case NUM_6:
                cardTypePriority = 6;
                break;
            case NUM_7:
                cardTypePriority = 7;
                break;
            case NUM_8:
                cardTypePriority = 8;
                break;
            case NUM_9:
                cardTypePriority = 9;
                break;
            case REVERSE:
                cardTypePriority = 10;
                break;
            case SKIP:
                cardTypePriority = 11;
                break;
            case TAKE_TWO:
                cardTypePriority = 12;
                break;
            case WILD:
                cardTypePriority = 0;
                break;
            case WILD_TAKE_FOUR:
                cardTypePriority = 1;
                break;
        }

        switch (card.getColor()) {
            case ANY:
                cardColorPriority = 13 * 4;   //13: 0-9 + reverse, skip, +2
                break;
            case BLUE:
                cardColorPriority = 13 * 3;
                break;
            case GREEN:
                cardColorPriority = 13 * 2;
                break;
            case YELLOW:
                cardColorPriority = 13;
                break;
            case RED:
                cardColorPriority = 0;
                break;
        }
        return cardColorPriority + cardTypePriority;
    }

    public void removeCard(Card card) {
        cards.remove(card);
        for (CardImage cardImage : cards) {
            if (cardImage.getCard() == card) {
                remove(cardImage);
                cards.remove(cardImage);
                return;
            }
        }
        resizeElements();
    }

    public Player getPlayer() {
        return player;
    }

    private void resizeElements() {
        playerPanel.setBounds((getWidth()-PLAYER_PANEL_WIDTH)/2,
                0,
                PLAYER_PANEL_WIDTH,
                PLAYER_PANEL_HEIGHT);

        cardWidth = getWidth() / cards.size() * 3 / 4;
        cardHeight = CardImage.getProportionHeight(cardWidth);
        if (cardHeight > getHeight() - PLAYER_PANEL_HEIGHT) {
            cardHeight = getHeight() - PLAYER_PANEL_HEIGHT;
            cardWidth = CardImage.getProportionWidth(cardHeight);
        }

        int cardsDelay = cardWidth / 10;
        int leftCardX = (getWidth() - ((cardWidth + cardsDelay) * cards.size())) / 2;

        for (int i = 0; i < cards.size(); i++) {
            CardImage card = cards.get(i);
            card.setBounds(i * (cardWidth + cardsDelay) + leftCardX, PLAYER_PANEL_HEIGHT, cardWidth, cardHeight);
        }
    }

    protected EventListenerList listenerList = new EventListenerList();

    public void addDropCardEventListener(DropCardListener listener) {
        listenerList.add(DropCardListener.class, listener);
    }

    public void removeDropCardEventListener(DropCardListener listener) {
        listenerList.remove(DropCardListener.class, listener);
    }

    void fireDropCardEvent(DropCardEvent evt) {
        Object[] listeners = listenerList.getListenerList();
        for (int i = 0; i < listeners.length; i = i + 2) {
            if (listeners[i] == DropCardListener.class) {
                ((DropCardListener) listeners[i + 1]).dropCardEventOccurred(evt);
            }
        }
    }

    public int getOneCardWidth() {
        return cardWidth;
    }

    public int getOneCardHeight() {
        return cardHeight;
    }

    public int getCardYLevel() {
        return PLAYER_PANEL_HEIGHT;
    }

    public int getLastCardX() {
        if (cards.isEmpty()) {
            return getWidth() / 2;
        }
        return cards.get(cards.size() - 1).getX();
    }

    public CardImage getCard(Card card) {
        for (CardImage ci : cards) {
            if (ci.getCard().equals(card)) {
                return ci;
            }
        }
        return null;
    }

    public Point getPlayerPanelLocation() {
        Point myLocation = getLocation();
        Point playerPanelLocation = playerPanel.getLocation();
        return new Point(myLocation.x + playerPanelLocation.x + playerPanel.getWidth()/2, myLocation.y + playerPanelLocation.y + playerPanel.getHeight()/2);
    }
}
